<!DOCTYPE html>
<html lang="zh-cn"><head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    
    <link href="/css/bootstrap.min.css" rel="stylesheet">
    <link href="/css/main.css" rel="stylesheet">

    <link rel="shortcut icon" type="image/x-icon" href="/img/favicon.ico" />

    <title>Go程序的字符串、数组和切片的应用 | wiseAI的小站</title>
</head><body><div class="container-fluid">
    <nav class="navbar fixed-top navbar-expand-sm navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand" href="/">
                <img src="/img/favicon.ico" alt="" width="30" height="24" class="d-inline-block align-text-top">
                wiseAI的小站
            </a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/articles/">文章</a>
                    </li>
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/categories/">分类</a>
                    </li>
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/tags/">关键字</a>
                    </li>
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/post/golang/">golang编程</a>
                    </li>
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/about/">关于</a>
                    </li>
                    
                </ul>
                <form class="d-flex">
                    <input id="search-query" class="form-control me-2" type="search" placeholder="Search for anything..." aria-label="Search">
                </form>
            </div>
        </div>
    </nav>
</div>




<div id="content">
<div class="container article">
	<h1>Go程序的字符串、数组和切片的应用</h1>
	<div class="post-meta">
		<div>
			
			
			By wiseai | 2022-07-31 | 3 minutes
		</div>
		<div class="tags">
			
			<a class="btn btn-light links btn-sm" href="/tags/%E7%BC%96%E7%A8%8B/">编程</a>
			
		</div>
	</div>
	<div>
		<div class="article-post">
			<h1 id="76-字符串数组和切片的应用">7.6 字符串、数组和切片的应用</h1>
<h2 id="761-从字符串生成字节切片">7.6.1 从字符串生成字节切片</h2>
<p>假设 <code>s</code> 是一个字符串（本质上是一个字节数组），那么就可以直接通过 <code>c := []byte(s)</code> 来获取一个字节的切片 <code>c</code> 。另外，您还可以通过 <code>copy()</code> 函数来达到相同的目的：<code>copy(dst []byte, src string)</code>。</p>
<p>同样的，还可以使用 for-range 来获得每个元素（Listing 7.13 — <a href="examples/chapter_7/for_string.go">for_string.go</a>）：</p>
<pre tabindex="0"><code>package main

import &#34;fmt&#34;

func main() {
    s := &#34;\u00ff\u754c&#34;
    for i, c := range s {
        fmt.Printf(&#34;%d:%c &#34;, i, c)
    }
}
</code></pre><p>输出：</p>
<pre><code>0:ÿ 2:界
</code></pre>
<p>我们知道，Unicode 字符会占用 2 个字节，有些甚至需要 3 个或者 4 个字节来进行表示。如果发现错误的 UTF8 字符，则该字符会被设置为 <code>U+FFFD</code> 并且索引向前移动一个字节。和字符串转换一样，您同样可以使用 <code>c := []int32(s)</code> 语法，这样切片中的每个 <code>int</code> 都会包含对应的 Unicode 代码，因为字符串中的每次字符都会对应一个整数。类似的，您也可以将字符串转换为元素类型为 <code>rune</code> 的切片：<code>r := []rune(s)</code>。</p>
<p>可以通过代码 <code>len([]int32(s))</code> 来获得字符串中字符的数量，但使用 <code>utf8.RuneCountInString(s)</code> 效率会更高一点。(参考 <a href="exercises/chapter_4/count_characters.go">count_characters.go</a>)</p>
<p>您还可以将一个字符串追加到某一个字节切片的尾部：</p>
<pre tabindex="0"><code>var b []byte
var s string
b = append(b, s...)
</code></pre><h2 id="762-获取字符串的某一部分">7.6.2 获取字符串的某一部分</h2>
<p>使用 <code>substr := str[start:end]</code> 可以从字符串 str 获取到从索引 <code>start</code> 开始到 <code>end-1</code> 位置的子字符串。同样的，<code>str[start:]</code> 则表示获取从 <code>start</code> 开始到 <code>len(str)-1</code> 位置的子字符串。而 <code>str[:end]</code> 表示获取从 0 开始到 <code>end-1</code> 的子字符串。</p>
<h2 id="763-字符串和切片的内存结构">7.6.3 字符串和切片的内存结构</h2>
<p>在内存中，一个字符串实际上是一个双字结构，即一个指向实际数据的指针和记录字符串长度的整数（见图 7.4）。因为指针对用户来说是完全不可见，因此我们可以依旧把字符串看做是一个值类型，也就是一个字符数组。</p>
<p>字符串 <code>string s = &quot;hello&quot;</code> 和子字符串 <code>t = s[2:3]</code> 在内存中的结构可以用下图表示：</p>
<p><img src="images/7.6_fig7.4.png" alt=""></p>
<h2 id="764-修改字符串中的某个字符">7.6.4 修改字符串中的某个字符</h2>
<p>Go 语言中的字符串是不可变的，也就是说 <code>str[index]</code> 这样的表达式是不可以被放在等号左侧的。如果尝试运行 <code>str[i] = 'D'</code> 会得到错误：<code>cannot assign to str[i]</code>。</p>
<p>因此，您必须先将字符串转换成字节数组，然后再通过修改数组中的元素值来达到修改字符串的目的，最后将字节数组转换回字符串格式。</p>
<p>例如，将字符串 <code>&quot;hello&quot;</code> 转换为 <code>&quot;cello&quot;</code>：</p>
<pre tabindex="0"><code>s := &#34;hello&#34;
c := []byte(s)
c[0] = &#39;c&#39;
s2 := string(c) // s2 == &#34;cello&#34;
</code></pre><p>所以，您可以通过操作切片来完成对字符串的操作。</p>
<h2 id="765-字节数组对比函数">7.6.5 字节数组对比函数</h2>
<p>下面的 <code>Compare()</code> 函数会返回两个字节数组字典顺序的整数对比结果，即 <code>0 if a == b, -1 if a &lt; b, 1 if a &gt; b</code>。</p>
<pre tabindex="0"><code>func Compare(a, b[]byte) int {
    for i:=0; i &lt; len(a) &amp;&amp; i &lt; len(b); i++ {
        switch {
        case a[i] &gt; b[i]:
            return 1
        case a[i] &lt; b[i]:
            return -1
        }
    }
    // 数组的长度可能不同
    switch {
    case len(a) &lt; len(b):
        return -1
    case len(a) &gt; len(b):
        return 1
    }
    return 0 // 数组相等
}
</code></pre><h2 id="766-搜索及排序切片和数组">7.6.6 搜索及排序切片和数组</h2>
<p>标准库提供了 <code>sort</code> 包来实现常见的搜索和排序操作。您可以使用 <code>sort</code> 包中的函数 <code>func Ints(a []int)</code> 来实现对 <code>int</code> 类型的切片排序。例如 <code>sort.Ints(arri)</code>，其中变量 <code>arri</code> 就是需要被升序排序的数组或切片。为了检查某个数组是否已经被排序，可以通过函数 <code>IntsAreSorted(a []int) bool</code> 来检查，如果返回 <code>true</code> 则表示已经被排序。</p>
<p>类似的，可以使用函数 <code>func Float64s(a []float64)</code> 来排序 <code>float64</code> 的元素，或使用函数 <code>func Strings(a []string)</code> 排序字符串元素。</p>
<p>想要在数组或切片中搜索一个元素，该数组或切片必须先被排序（因为标准库的搜索算法使用的是二分法）。然后，您就可以使用函数 <code>func SearchInts(a []int, n int) int</code> 进行搜索，并返回对应结果的索引值。</p>
<p>当然，还可以搜索 <code>float64</code> 和字符串：</p>
<pre tabindex="0"><code>func SearchFloat64s(a []float64, x float64) int
func SearchStrings(a []string, x string) int
</code></pre><p>您可以通过查看 <a href="http://golang.org/pkg/sort/">官方文档</a> 来获取更详细的信息。</p>
<p>这就是如何使用 <code>sort</code> 包的方法，我们会在<a href="11.7.md">第 11.7 节</a> 对它的细节进行深入，并实现一个属于我们自己的版本。</p>
<h2 id="767-append-函数常见操作">7.6.7 append() 函数常见操作</h2>
<p>我们在<a href="07.5.md">第 7.5 节</a>提到的 <code>append()</code> 非常有用，它能够用于各种方面的操作：</p>
<ol>
<li>
<p>将切片 <code>b</code> 的元素追加到切片 <code>a</code> 之后：<code>a = append(a, b...)</code></p>
</li>
<li>
<p>复制切片 <code>a</code> 的元素到新的切片 <code>b</code> 上：</p>
<pre tabindex="0"><code>b = make([]T, len(a))
copy(b, a)
</code></pre></li>
<li>
<p>删除位于索引 <code>i</code> 的元素：<code>a = append(a[:i], a[i+1:]...)</code></p>
</li>
<li>
<p>切除切片 <code>a</code> 中从索引 <code>i</code> 至 <code>j</code> 位置的元素：<code>a = append(a[:i], a[j:]...)</code></p>
</li>
<li>
<p>为切片 <code>a</code> 扩展 <code>j</code> 个元素长度：<code>a = append(a, make([]T, j)...)</code></p>
</li>
<li>
<p>在索引 <code>i</code> 的位置插入元素 <code>x</code>：<code>a = append(a[:i], append([]T{x}, a[i:]...)...)</code></p>
</li>
<li>
<p>在索引 <code>i</code> 的位置插入长度为 <code>j</code> 的新切片：<code>a = append(a[:i], append(make([]T, j), a[i:]...)...)</code></p>
</li>
<li>
<p>在索引 <code>i</code> 的位置插入切片 <code>b</code> 的所有元素：<code>a = append(a[:i], append(b, a[i:]...)...)</code></p>
</li>
<li>
<p>取出位于切片 <code>a</code> 最末尾的元素 <code>x</code>：<code>x, a = a[len(a)-1], a[:len(a)-1]</code></p>
</li>
<li>
<p>将元素 <code>x</code> 追加到切片 <code>a</code>：<code>a = append(a, x)</code></p>
</li>
</ol>
<p>因此，您可以使用切片和 <code>append()</code> 操作来表示任意可变长度的序列。</p>
<p>从数学的角度来看，切片相当于向量，如果需要的话可以定义一个向量作为切片的别名来进行操作。</p>
<p>如果您需要更加完整的方案，可以学习一下 Eleanor McHugh 编写的几个包：<a href="http://github.com/feyeleanor/slices"><code>slices</code></a>、<a href="http://github.com/feyeleanor/chain"><code>chain</code></a> 和 <a href="http://github.com/feyeleanor/lists"><code>lists</code></a>。</p>
<h2 id="768-切片和垃圾回收">7.6.8 切片和垃圾回收</h2>
<p>切片的底层指向一个数组，该数组的实际容量可能要大于切片所定义的容量。只有在没有任何切片指向的时候，底层的数组内存才会被释放，这种特性有时会导致程序占用多余的内存。</p>
<p><strong>示例</strong> 函数 <code>FindDigits()</code> 将一个文件加载到内存，然后搜索其中所有的数字并返回一个切片。</p>
<pre tabindex="0"><code>var digitRegexp = regexp.MustCompile(&#34;[0-9]+&#34;)

func FindDigits(filename string) []byte {
    b, _ := ioutil.ReadFile(filename)
    return digitRegexp.Find(b)
}
</code></pre><p>这段代码可以顺利运行，但返回的 <code>[]byte</code> 指向的底层是整个文件的数据。只要该返回的切片不被释放，垃圾回收器就不能释放整个文件所占用的内存。换句话说，一点点有用的数据却占用了整个文件的内存。</p>
<p>想要避免这个问题，可以通过拷贝我们需要的部分到一个新的切片中：</p>
<pre tabindex="0"><code>func FindDigits(filename string) []byte {
   b, _ := ioutil.ReadFile(filename)
   b = digitRegexp.Find(b)
   c := make([]byte, len(b))
   copy(c, b)
   return c
}
</code></pre><p>事实上，上面这段代码只能找到第一个匹配正则表达式的数字串。要想找到所有的数字，可以尝试下面这段代码：</p>
<pre tabindex="0"><code>func FindFileDigits(filename string) []byte {
   fileBytes, _ := ioutil.ReadFile(filename)
   b := digitRegexp.FindAll(fileBytes, len(fileBytes))
   c := make([]byte, 0)
   for _, bytes := range b {
      c = append(c, bytes...)
   }
   return c
}
</code></pre><p><strong>练习 7.12</strong> <a href="exercises/chapter_7/split_string.go">split_string.go</a></p>
<p>编写一个函数，要求其接受两个参数，原始字符串 <code>str</code> 和分割索引 <code>i</code>，然后返回两个分割后的字符串。</p>
<p><strong>练习 7.13</strong> <a href="exercises/chapter_7/string_split2.go">string_split2.go</a></p>
<p>假设有字符串 <code>str</code>，那么 <code>str[len(str)/2:] + str[:len(str)/2]</code> 的结果是什么？</p>
<p><strong>练习 7.14</strong> <a href="exercises/chapter_7/string_reverse.go">string_reverse.go</a></p>
<p>编写一个程序，要求能够反转字符串，即将 <code>&quot;Google&quot;</code> 转换成 <code>&quot;elgooG&quot;</code>（提示：使用 <code>[]byte</code> 类型的切片）。</p>
<p>如果您使用两个切片来实现反转，请再尝试使用一个切片（提示：使用交换法）。</p>
<p>如果您想要反转 Unicode 编码的字符串，请使用 <code>[]int32</code> 类型的切片。</p>
<p><strong>练习 7.15</strong> <a href="exercises/chapter_7/uniq.go">Q29_uniq.go</a></p>
<p>编写一个程序，要求能够遍历一个字符数组，并将当前字符和前一个字符不相同的字符拷贝至另一个数组。</p>
<p><strong>练习 7.16</strong> <a href="exercises/chapter_7/bubblesort.go">bubblesort.go</a></p>
<p>编写一个程序，使用冒泡排序的方法排序一个包含整数的切片（算法的定义可参考 <a href="http://en.wikipedia.org/wiki/Bubble_sort">维基百科</a>）。</p>
<p><strong>练习 7.17</strong> <a href="exercises/chapter_7/map_function.go">map_function.go</a></p>
<p>在函数式编程语言中，一个 map-function 是指能够接受一个函数原型和一个列表，并使用列表中的值依次执行函数原型，公式为：<code>map ( F(), (e1,e2, . . . ,en) ) = ( F(e1), F(e2), ... F(en) )</code>。</p>
<p>编写一个函数 <code>mapFunc</code> 要求接受以下 2 个参数：</p>
<ul>
<li>一个将整数乘以 10 的函数</li>
<li>一个整数列表</li>
</ul>
<p>最后返回保存运行结果的整数列表。</p>

		</div>
	</div>
</div>


<div class="container">
    
    <div class="row">
        
        <div class="col-5">
            <a class="page-link link-dark text-end dh" href="/post/golang/2022.07.30-%E5%88%87%E7%89%87%E7%9A%84%E5%A4%8D%E5%88%B6%E4%B8%8E%E8%BF%BD%E5%8A%A0/">
                <h5>前一篇</h5><br>
                Go程序的切片的复制与追加
            </a>            
        </div>
        
        <div class="col-2">
        </div>
        
        <div class="col-5">
            <a class="page-link link-dark text-start dh" href="">
                <h5>没有了</h5><br>
            </a>            
        </div>
        
    </div>
    
</div>

        </div><br><br>
<footer class="container">
    <h2>友情链接</h2>
    <hr>
    <nav class="nav nav-pills flex-column flex-sm-row">
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/gnzg/index.html" target="_blank">孤鸟之歌</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/mm/index.html" target="_blank">生成随机字符</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/md/index.html" target="_blank">MarkDown</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://gitee.com/" target="_blank">Gitee</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://github.com/" target="_blank">Github</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.aliyun.com/" target="_blank">阿里云</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://cloud.tencent.com/" target="_blank">腾讯云</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.oschina.net/" target="_blank">OSCHINA开源中国</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://gitee.com/wiseai/the-way-to-go_ZH_CN/blob/master/eBook/directory.md" target="_blank">the way to go</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://topgoer.com/" target="_blank">golang文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://goframe.org/display/gf" target="_blank">GoFrame</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.aliyundrive.com/" target="_blank">阿里云盘</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://cn.vuejs.org/" target="_blank">vue3文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://element-plus.gitee.io/zh-CN/" target="_blank">element-plus文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.runoob.com/vue3/vue3-tutorial.html" target="_blank">vue3菜鸟教程</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://v5.bootcss.com/" target="_blank">bootstrap v5 中文文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.bootstrap.cn/" target="_blank">bootstrap文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://caddy2.dengxiaolong.com/docs/" target="_blank">caddy中文教程</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.58pic.com/" target="_blank">千图</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://ifonts.com/" target="_blank">iFonts</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://marketing.qiniu.com/" target="_blank">七牛云</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.ixigua.com/" target="_blank">西瓜视频</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/yugang/index.html" target="_blank">鱼缸计算</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://justcc.mengkang.net/#/" target="_blank">C语言JustCC</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/pptist/" target="_blank">PPTist</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="/index.xml" target="_blank">RSS</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.kancloud.cn/idcpj/python/418553" target="_blank">参考资料</a>
        
    </nav>

    <div class="copyright text-center">
      <span class="power-by">
        Powered by <a class="links" href="https://gohugo.io" target="_blank">Hugo</a>
    </span>
    <span>|</span>
    <span>
        Theme - <a class="links" href="https://github.com/wiseai-go/blog-hugo" target="_blank">WiseAI</a>
    </span>
    <br>
    <span class="copyright-year">
        &copy;
        
        2017 -
        2023<span>
            陇ICP备15000157号
            
        </span></span>

</div>
</footer>
<script src="/js/bootstrap.bundle.min.js"></script>


</body>
</html>
